package com.smasher.net.util;

import android.Manifest;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.util.Log;

import androidx.annotation.Nullable;
import androidx.annotation.RequiresPermission;

import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.util.List;

/**
 * @author moyu
 * @date 2017/3/13
 */
public class NetworkUtil {

    public static final String TAG = NetworkUtil.class.getSimpleName();

    private static boolean debug = false;

    public static void setDebug(boolean debug) {
        NetworkUtil.debug = debug;
    }

    // 提取公共获取NetworkCapabilities方法
    @Nullable
    private static NetworkCapabilities getNetworkCapabilities(Context context) {
        ConnectivityManager connectivityManager = (ConnectivityManager)
                context.getSystemService(Context.CONNECTIVITY_SERVICE);
        if (connectivityManager == null) return null;
        Network network = connectivityManager.getActiveNetwork();
        return connectivityManager.getNetworkCapabilities(network);
    }


    /**
     * 网络是否可用
     *
     * @return 网络是否连接并且可用
     */
    @RequiresPermission(Manifest.permission.ACCESS_NETWORK_STATE)
    public static Boolean isNetworkReachable(Context context) {
        NetworkCapabilities networkCapabilities = getNetworkCapabilities(context);
        if (networkCapabilities != null) {
            // 是否能够访问互联网
            boolean hasInternet = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
            if (debug) {
                Log.d(TAG, "Internet Access: " + hasInternet);
            }

            // 是否不受限制
            boolean hasNotRestricted = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
            if (debug) {
                Log.d(TAG, "Not Restricted: " + hasNotRestricted);
            }

            //是否已经验证为可正常工作
            boolean hasValidated = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
            if (debug) {
                Log.d(TAG, "Validated: " + hasValidated);
            }
            return hasInternet && hasNotRestricted && hasValidated;
        }

        return false;
    }

    /**
     * 检查是否连接网络
     *
     * @return 是否连接到网络
     */
    @RequiresPermission(Manifest.permission.ACCESS_NETWORK_STATE)
    public static boolean isNetworkAvailable(Context context) {
        NetworkCapabilities networkCapabilities = getNetworkCapabilities(context);
        if (networkCapabilities != null) {
            // 是否能够访问互联网
            boolean hasInternet = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
            if (debug) {
                Log.i(TAG, "CAPABILITY Internet Access: " + hasInternet);
            }

            // 是否不受限制
            boolean hasNotRestricted = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
            if (debug) {
                Log.i(TAG, "CAPABILITY Not Restricted: " + hasNotRestricted);
            }

            //是否被认为是可信的
            boolean hasTrusted = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED);
            if (debug) {
                Log.i(TAG, "CAPABILITY Trusted: " + hasTrusted);
            }

            //是否已经验证为可正常工作
            boolean hasValidated = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
            if (debug) {
                Log.i(TAG, "CAPABILITY Validated: " + hasValidated);
            }

            //是否连接蜂窝网络
            boolean hasCellular = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR);
            if (debug) {
                Log.i(TAG, "TRANSPORT Cellular: " + hasCellular);
            }

            //是否连WIFI网络
            boolean hasWifi = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
            if (debug) {
                Log.i(TAG, "TRANSPORT Wifi: " + hasWifi);
            }

            //是否连以太网络
            boolean hasEthernet = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET);
            if (debug) {
                Log.i(TAG, "TRANSPORT Ethernet: " + hasEthernet);
            }
            return hasInternet;
        }
        return false;
    }

    /**
     * 判断当前的网络类型是wifi，流量还是有线网络
     *
     * @param context context
     * @return String
     */
    @RequiresPermission(Manifest.permission.ACCESS_NETWORK_STATE)
    public static String getCurrentNetworkType(Context context) {
        NetworkCapabilities networkCapabilities = getNetworkCapabilities(context);
        if (networkCapabilities == null) {
            if (debug){
                Log.d(TAG, "No network capabilities found");
            }
            return "None";
        } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
            if (debug){
                Log.d(TAG, "Current network type: Wifi");
            }
            return "Wifi";
        } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
            if (debug){
                Log.d(TAG, "Current network type: Mobile");
            }
            return "Mobile";
        } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) {
            if (debug){
                Log.d(TAG, "Current network type: Ethernet");
            }
            return "Ethernet";
        }
        if (debug){
            Log.d(TAG, "Current network type: Other");
        }
        return "Other";
    }

    /**
     * 是否是wifi
     *
     * @return boolean
     */
    @RequiresPermission(Manifest.permission.ACCESS_NETWORK_STATE)
    public static boolean isWifiAvailable(Context context) {
        try {
            NetworkCapabilities networkCapabilities = getNetworkCapabilities(context);
            if (networkCapabilities != null) {
                // 是否连WIFI网络
                boolean hasWifi = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
                if (debug){
                    Log.d(TAG, "TRANSPORT Wifi: " + hasWifi);
                }

                // 是否能够访问互联网
                boolean hasInternet = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
                // 是否不受限制
                boolean hasNotRestricted = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
                if (debug){
                    Log.i(TAG, "CAPABILITY Internet Access: " + hasInternet + ", Not Restricted: " + hasNotRestricted);
                }
                return hasWifi && hasInternet && hasNotRestricted;
            }
        } catch (Exception ex) {
            Log.e(TAG, "isWifiAvailable: ", ex);
        }
        return false;
    }

    /**
     * 是否是移动网络
     *
     * @return boolean
     */
    @RequiresPermission(Manifest.permission.ACCESS_NETWORK_STATE)
    public static boolean isMobileNetwork(Context context) {
        try {
            NetworkCapabilities networkCapabilities = getNetworkCapabilities(context);
            if (networkCapabilities != null) {
                // 是否连接蜂窝网络
                boolean hasCellular = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR);
                if (debug){
                    Log.d(TAG, "TRANSPORT Cellular: " + hasCellular);
                }

                // 是否能够访问互联网
                boolean hasInternet = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
                // 是否不受限制
                boolean hasNotRestricted = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
                if (debug){
                    Log.i(TAG, "CAPABILITY Internet Access: " + hasInternet + ", Not Restricted: " + hasNotRestricted);
                }

                return hasCellular && hasInternet && hasNotRestricted;
            }
        } catch (Exception ex) {
            Log.e(TAG, "isMobileNetwork: ", ex);
        }
        return false;
    }

    /**
     * 获取IP地址
     *
     * @return String
     */
    @RequiresPermission(Manifest.permission.ACCESS_NETWORK_STATE)
    public static String getIPAddress(Context context) {
        ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        if (connectivityManager == null) {
            if (debug) {
                Log.d(TAG, "ConnectivityManager is null");
            }
            return "";
        }

        Network activeNetwork = connectivityManager.getActiveNetwork();
        if (activeNetwork != null) {
            LinkProperties linkProperties = connectivityManager.getLinkProperties(activeNetwork);
            if (linkProperties != null) {
                List<LinkAddress> addresses = linkProperties.getLinkAddresses();
                for (LinkAddress address : addresses) {
                    InetAddress inetAddress = address.getAddress();
                    if (!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet4Address) {
                        if (debug) {
                            Log.d(TAG, "IPv4 Address: " + inetAddress.getHostAddress());
                        }
                        return inetAddress.getHostAddress();
                    }
                }
                // 如果没有找到IPv4地址，则尝试查找IPv6地址
                for (LinkAddress address : addresses) {
                    InetAddress inetAddress = address.getAddress();
                    if (!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet6Address) {
                        if (debug) {
                            Log.d(TAG, "IPv6 Address: " + inetAddress.getHostAddress());
                        }
                        return inetAddress.getHostAddress();
                    }
                }
            }
        }
        if (debug) {
            Log.d(TAG, "No IP address found");
        }
        return "";
    }

    /**
     * 将得到的int类型的IP转换为String类型
     *
     * @param ip ip
     * @return String
     */
    private static String intIP2StringIP(int ip) {
        return (ip & 0xFF) + "." +
                ((ip >> 8) & 0xFF) + "." +
                ((ip >> 16) & 0xFF) + "." +
                (ip >> 24 & 0xFF);
    }

    //==================================== 分割线 =================================================

    /**
     * 注册网络监听器
     *
     * @param context  context
     * @param callback callback
     */
    public void registerNetworkListener(Context context, ConnectivityManager.NetworkCallback callback) {
        ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkRequest.Builder builder = new NetworkRequest.Builder();
        NetworkRequest request = builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
                .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
                .build();
        connectivityManager.requestNetwork(request, callback);
        if (debug) {
            Log.d(TAG, "Network listener registered");
        }
    }

    /**
     * 取消注册网络监听器
     *
     * @param context  context
     * @param callback callback
     */
    public static void unRegisterNetworkListener(Context context, ConnectivityManager.NetworkCallback callback) {
        ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        connectivityManager.unregisterNetworkCallback(callback);
        if (debug) {
            Log.d(TAG, "Network listener unregistered");
        }
    }
}